/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include "pagememhandler.h"

#include <kerneldebugconsole.h>
#include <bootoutput.h>
#include <machine/pc/memory/physicalpagemanager.h>
#include <machine/pc/memory/virtualpagemanager.h>
#include <machine/machine.h>

PLPageMemHandler::PLPageMemHandler() : m_empty(), m_lastVirtualAddress(0) {
	m_headerSize = sizeof(MemHeader);
}

void PLPageMemHandler::setLastVirtualAddress(uint32_t lastVirtualAddress) {
	m_lastVirtualAddress = lastVirtualAddress;
	m_lastVirtualPage    = lastVirtualAddress;
	PLKernelDebugConsole::instance().printf("\n   Set last virtual address: 0x%x", lastVirtualAddress);
}

void *PLPageMemHandler::alloc(size_t size) {
	if(m_lastVirtualPage - m_lastVirtualAddress <= (size + m_headerSize)) {
		PhysicalPageManager &phyman = PhysicalPageManager::instance();
		uint32_t nextPage = phyman.findNextFree();
		phyman.setUsed(nextPage);
		PLVirtualPageManager *vman = PLMachine::instance().kernelVirtualPageManager();
		vman->mapPage((void *)(nextPage * vman->pageSize()), (void *)m_lastVirtualPage, PLVirtualPageManager::PageTablePresent | PLVirtualPageManager::PageTableReadWrite);
		m_lastVirtualPage += vman->pageSize();
		return alloc(size);
	}
	((MemHeader *)m_lastVirtualAddress)->size = size;
	void *ret = (void *)(m_lastVirtualAddress + m_headerSize);
	m_lastVirtualAddress += (size + m_headerSize);
	return ret;
}

size_t PLPageMemHandler::sizeOfMem(void *mem) {
	MemHeader *header = (MemHeader *)(((uint32_t)mem) - m_headerSize);
	return header->size;
}

void PLPageMemHandler::dealloc(void *mem) {
    MemHeader *header = (MemHeader *)(((uint32_t)mem) - m_headerSize);
	m_empty.append(header);
}
